# ifndef _WEBSOCKET_CLIENT_H
# define _WEBSOCKET_CLIENT_H

#include <cstdlib>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <system_error>
#include <deque>
#include <mutex>

#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/strand.hpp>

namespace beast = boost::beast;         // from <boost/beast.hpp>
namespace http = beast::http;           // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio;            // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>

template<typename Msg, typename CallBack>
class WebSocketClient : public std::enable_shared_from_this<WebSocketClient<Msg, CallBack>>
{
public:
    WebSocketClient(std::shared_ptr<CallBack> callBack);
    ~WebSocketClient();

    void run(const std::string host, const std::string port, const std::string target);
    void onResolve(beast::error_code ec, tcp::resolver::results_type results);
    void onConnect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep);
    void onHandshake(beast::error_code ec);
    void onRead(beast::error_code ec, std::size_t bytesTransferred);
    void sedMsg(std::shared_ptr<Msg> msg);
    void stop();


private:
    net::io_context ioc_;
    tcp::resolver resolver_;
    websocket::stream<beast::tcp_stream> ws_;
    beast::flat_buffer buffer_;
    std::string host_;
    std::string target_;
    std::shared_ptr<CallBack> callBack_;

    std::mutex queueMutex_;
    std::deque<Msg> MsgQueue_;

};

# endif //_WEBSOCKET_CLIENT_H